home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / BCCAPP.ARJ / FIELD.C < prev    next >
C/C++ Source or Header  |  1991-09-15  |  11KB  |  591 lines

  1. /*
  2.  *
  3.  * Field editing system.
  4.  *
  5.  * (C) 1990 Vision Software
  6.  *
  7.  * $Id: field.c 1.102 91/05/04 17:19:08 pcalvin beta $
  8.  *
  9.  * Comments:
  10.  *
  11.  * This class provides EDIT with the individual field control.  In the
  12.  * future, we may be used by other classes that require formated input..
  13.  *
  14.  * Bugs:
  15.  *
  16.  * Probably, none documented.
  17.  *
  18.  */
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <string.h>
  22.  
  23. #include <stdhdr.h>
  24.  
  25. #include <adl.h>
  26. #include <menu.h>
  27. #include <field.h>
  28.  
  29. #include "lowlevel.h"
  30.  
  31. /*
  32.  * Title/Information field contruction..
  33.  */
  34. IF::IF(WINDOW &rwndDest,ROW rowStart,COL colStart,SZ sz) : rwnd(rwndDest)
  35.     {
  36.     szMessage = sz;
  37.     row = rowStart;
  38.     col = colStart;
  39.     }
  40.  
  41. /*
  42.  * Say the title/message field
  43.  */
  44. VOID IF::SayMessage()
  45.     {
  46.     rwnd.SayAt(RowEdit(),ColLeft(),szMessage);
  47.     }
  48.  
  49. /*
  50.  * Answers with the row for this field..
  51.  */
  52. ROW IF::RowEdit()
  53.     {
  54.     return (row);
  55.     }
  56.  
  57. /*
  58.  * Answers with left edge of this field..
  59.  */
  60. COL IF::ColLeft()
  61.     {
  62.     return (col);
  63.     }
  64.  
  65. /*
  66.  * Answers with the right edge of this field..
  67.  */
  68. COL IF::ColRight()
  69.     {
  70.     return (col + strlen(szMessage));
  71.     }
  72.  
  73. /*
  74.  * Edit field construction.
  75.  */
  76. ED::ED(WINDOW &rwnd,ROW rowStart,COL colStart,SZ szMsg,SZ szDest,CCH cch,SZ szHelpInfo,CENT cent,PENT pent,CENT centDefault) : IF(rwnd,rowStart,colStart,szMsg)
  77.     {
  78.     Assert(szMsg != szNil);
  79.     AssertSz(centDefault < cent,"Default for field not within range");
  80.  
  81.     sz = szDest;
  82.     szHelp = szHelpInfo;
  83.     dcol = strlen(szMsg) + 2;
  84.     szPicture = szNil;
  85.     chPicture = 'X';
  86.     cchMax = cch;
  87.     cchMac = cchNil;
  88.     cchCurrent = cchNil;
  89.     pfnValid = pfnNil;
  90.     pvValid = pvNil;
  91.     centValid = cent;
  92.     pentValid = pent;
  93.     szDefault = pent[centDefault].sz;
  94.     SetUnchanged();
  95.     SetCursor();
  96.     fCareAboutChanges = fTrue;
  97.     fNumeric = fFalse;
  98.     }
  99.  
  100. ED::ED(WINDOW &rwnd,ROW rowStart,COL colStart,SZ szMsg,SZ szDest,CHAR ch,CCH cch,SZ szHelpInfo,SZ szDflt) : IF(rwnd,rowStart,colStart,szMsg)
  101.     {
  102.     Assert(szMsg != szNil);
  103.  
  104.     sz = szDest;
  105.     szHelp = szHelpInfo;
  106.     dcol = strlen(szMsg) + 2;
  107.     szPicture = szNil;
  108.     chPicture = ch;
  109.     cchMax = cch;
  110.     cchMac = cchNil;
  111.     cchCurrent = cchNil;
  112.     pfnValid = pfnNil;
  113.     pvValid = pvNil;
  114.     centValid = centNil;
  115.     pentValid = pentNil;
  116.     szDefault = szDflt;
  117.     SetUnchanged();
  118.     SetCursor();
  119.     fCareAboutChanges = fTrue;
  120.     fNumeric = (ch == '9');
  121.     }
  122.  
  123. ED::ED(WINDOW &rwnd,ROW rowStart,COL colStart,SZ szMsg,SZ szDest,SZ szPic,SZ szHelpInfo,SZ szDflt) : IF(rwnd,rowStart,colStart,szMsg)
  124.     {
  125.     Assert(szPic != szNil);
  126.     Assert(szMsg != szNil);
  127.  
  128.     sz = szDest;
  129.     szHelp = szHelpInfo;
  130.     szPicture = szPic;
  131.     dcol = strlen(szMsg) + 2;
  132.     cchMax = strlen(szPicture);
  133.     cchMac = cchNil;
  134.     cchCurrent = cchNil;
  135.     pfnValid = pfnNil;
  136.     pvValid = pvNil;
  137.     centValid = centNil;
  138.     pentValid = pentNil;
  139.     szDefault = szDflt;
  140.     SetUnchanged();
  141.     SetCursor();
  142.     fCareAboutChanges = fTrue;
  143.     fNumeric = fFalse;
  144.     }
  145.  
  146. /*
  147.  * Answers if the contents are valid given whatever validation procedure..
  148.  */
  149. BOOL ED::FValidate()
  150.     {
  151.     BOOL fValid = fTrue;
  152.  
  153.     if (pentValid != pentNil && !FInRange())
  154.         fValid = FValidateRange();
  155.     else if (pfnValid != pfnNil)
  156.         fValid = FValidateFunction();
  157.  
  158.     return (fValid);
  159.     }
  160.  
  161. /*
  162.  * Non-standard fields may be modified after being created..
  163.  */
  164. VOID ED::Adjust(PFN pfn,VOID *pv,BOOL fCareIfFieldChanges)
  165.     {
  166.     pfnValid = pfn;
  167.     pvValid = pv;
  168.     fCareAboutChanges = fCareIfFieldChanges;
  169.     }
  170.  
  171. /*
  172.  * Replaces the current help information..
  173.  */
  174. VOID ED::UpdateHelp(HELP &rhelp)
  175.     {
  176.     rhelp.Replace(szHelp);
  177.     }
  178.  
  179. /*
  180.  * Checks to see if the current input is in the validation array.  This
  181.  * Array could be in any order, so a linear search is needed..
  182.  */
  183. BOOL ED::FInRange()
  184.     {
  185.     BOOL fFound = fFalse;
  186.     PENT pent = pentValid;
  187.     CENT cent = centNil;
  188.  
  189.     /*
  190.      * We simply traverse the array, looking for a match.  To avoid
  191.      * to many strcmp()s, it is only called if the first letter matches..
  192.      */
  193.     while (!fFound && cent < centValid)
  194.         {
  195.         if (*sz == *pent->sz && strcmp(sz,pent->sz) == 0)
  196.             {
  197.             fFound = fTrue;
  198.             }
  199.         else
  200.             {
  201.             cent++;
  202.             pent++;
  203.             }
  204.         }
  205.  
  206.     return (fFound);
  207.     }
  208.  
  209. /*
  210.  * Answers if SZ is in the given list of choices..
  211.  * In addition, to direct the user to the correct title, that title
  212.  * is presented here in white..
  213.  */
  214. BOOL ED::FValidateRange()
  215.     {
  216.     ROW row = rwnd.RowQuery() + RowEdit() - 2;
  217.     COL col = rwnd.ColQuery() + ColLeft() - 1;
  218.     POPUP pop(row,col,centValid,pentValid);
  219.     CENT cent = pop.CentGet();
  220.     BOOL fSelected = fFalse;
  221.  
  222.     if (cent != centError)
  223.         {
  224.         strcpy(sz,pentValid[cent].sz);
  225.         fChanges = fTrue;
  226.         SayEdit(fTrue);
  227.         fSelected = fTrue;
  228.         }
  229.  
  230.     return (fSelected);
  231.     }
  232.  
  233. /*
  234.  * Answers if SZ is legal based upon the function call..
  235.  */
  236. BOOL ED::FValidateFunction()
  237.     {
  238.     return (pfnValid(sz,pvValid));
  239.     }
  240.  
  241. /*
  242.  * Answers with the picture character for this position in the edit
  243.  */
  244. CHAR ED::ChPicture()
  245.     {
  246.     if (szPicture == szNil)
  247.         return (chPicture);
  248.     else
  249.         return (szPicture[cchCurrent]);
  250.     }
  251.  
  252. /*
  253.  * Updates display for the current edit.  Redraws the entire field.  Also,
  254.  * asserts the field length is set properly..
  255.  */
  256. VOID ED::SayEdit(BOOL fCurrent)
  257.     {
  258.     CURSOR crs(fFalse);
  259.     
  260.     /*
  261.      * Assert the length is setup properly
  262.      */
  263.     cchMac = cchNil;
  264.  
  265.     /*
  266.      * Maximum current width is field width..
  267.      */
  268.     while (sz[cchMac] != chNil && cchMac < cchMax)
  269.         cchMac++;
  270.  
  271.     /*
  272.      *    Remove/Insert leading WS depending if we are editing a numeric field.
  273.      */
  274.     if (fNumeric)
  275.         {
  276.         Verify(fCurrent ? FStripLeader() : FInsertLeader());
  277.         }
  278.         
  279.     /*
  280.      * Left Justify output within field, and determine the display colour
  281.      */
  282.     SZ szOutput = SzTempPaddedFromSzCch(sz,cchMax);
  283.     CO coBack = (fCurrent) ? coGreen : coCyan;
  284.  
  285.     /*
  286.      * Output..
  287.      */
  288.     rwnd.SayAt(RowEdit(),ColLeft(),szOutput,coBlack,coBack);
  289.     }
  290.  
  291. /*
  292.  *    Strips leading WS from the edit
  293.  */
  294. BOOL ED::FStripLeader()
  295.     {
  296.     CCH cch = cchNil;
  297.  
  298.     /*
  299.      *    Search for the end..
  300.      */
  301.     while (cch < cchMac && sz[cch] == chSpace)
  302.         cch++;
  303.         
  304.     /*
  305.      *    Now, copy over..
  306.      */
  307.     if (cch != cchNil && cch < cchMac)
  308.         {
  309.         CCH cchNewMac = cchMac - cch;
  310.         
  311.         memmove(&sz[cchNil],&sz[cch],cchNewMac);
  312.         sz[cchNewMac] = chNil;
  313.         cchMac = cchNewMac;
  314.         }
  315.         
  316.     return (fTrue);
  317.     }
  318.  
  319. /*
  320.  *    Inserts leading WS into the header
  321.  */
  322. BOOL ED::FInsertLeader()
  323.     {
  324.     if (cchMac < cchMax)
  325.         {
  326.         CCH cch = cchMax - cchMac;
  327.  
  328.         memmove(&sz[cch],&sz[cchNil],cchMac);
  329.         memset(sz,chSpace,cch);
  330.         }
  331.  
  332.     return (fTrue);
  333.     }
  334.     
  335. /*
  336.  *    Sets the cursor at the far right of the edit.
  337.  */
  338. VOID ED::SetCursor()    
  339.     {
  340.     cchCurrent = cchNil;
  341.  
  342.     /*
  343.      *    Maximum is field width..
  344.      */
  345.     while (sz[cchCurrent] != chNil && cchCurrent < cchMax)
  346.         cchCurrent++;
  347.     }
  348.      
  349.  
  350. /*
  351.  * Inserts a character at the current position
  352.  */
  353. BOOL ED::FInsertCd(CD cd)
  354.     {
  355.     Assert(cchMac <= cchMax);
  356.     
  357.     CHAR ch = (CHAR)cd;
  358.  
  359.     if (FValidChCh(ch,ChPicture()))
  360.         {
  361.         /*
  362.          *    Do not write past the end of the region..
  363.          */
  364.         if (cchCurrent >= cchMax)
  365.             cchCurrent--;
  366.  
  367.         /*
  368.          *    Make room for this new character.
  369.          */
  370.         for (CCH cch = cchMac; cch > cchCurrent; cch--)
  371.             {
  372.             if (cch < cchMax)
  373.                 sz[cch] = sz[cch-1];
  374.             }
  375.             
  376.         /* 
  377.          *    Now, insert this character..
  378.          */
  379.         sz[cchCurrent] = ch;
  380.         
  381.         /*
  382.          *    Adjust floating length..
  383.          */
  384.         if (cchMac < cchMax)
  385.             cchMac++;
  386.             
  387.         /*
  388.          *    Don't forget the \0 at the end if the key
  389.          */
  390.         if (cchMac < cchMax)    
  391.             sz[cchMac] = chNil;
  392.             
  393.         SayEdit(fTrue);
  394.         fChanges = fTrue;
  395.         CursorRight();
  396.         }
  397.  
  398.     return (fTrue);
  399.     }
  400.  
  401. /*
  402.  *    Cursor manipulation functions
  403.  * Right: Must be careful if cchMac == cchMax
  404.  */
  405. VOID ED::CursorRight()
  406.     {
  407.     cchCurrent++;
  408.     
  409.     /*
  410.      *    Now, assert it is within range..
  411.      */    
  412.     if (cchCurrent > cchMac)
  413.         cchCurrent--;
  414.     }
  415.  
  416.  
  417. /*
  418.  *    Left: Trivial..
  419.  */
  420. VOID ED::CursorLeft()
  421.     {
  422.     if (cchCurrent > cchNil)
  423.         cchCurrent--;
  424.     }
  425.  
  426.  
  427. /*
  428.  * Deletes the current character
  429.  */
  430. BOOL ED::FDelete()
  431.     {
  432.     if (cchCurrent > 0)
  433.         {
  434.         cchCurrent -= 1;
  435.         fChanges = fTrue;
  436.         if (DcolOffset() != 0)
  437.             rwnd.SetRowCol(RowEdit(),ColEdit());
  438.  
  439.         rwnd.PutCh(' ',coBlack,coGreen);
  440.         }
  441.     else if (cchMax == 1)
  442.         {
  443.         fChanges = fTrue;
  444.         rwnd.PutCh(' ',coBlack,coGreen);
  445.         }
  446.  
  447.     /*
  448.      * No matter where in the edit we were, or what size the field
  449.      * is, set that character to chNil
  450.      */
  451.     sz[cchCurrent] = chNil;
  452.  
  453.     return (fTrue);
  454.     }
  455.  
  456. /*
  457.  * Cursor positioning.  DcolOffset computes where to place the cursor.
  458.  * Normally, this is one character ahead of the current.  If we are
  459.  * are at the limit of the field, it is simply there..
  460.  */
  461. COL ED::DcolOffset()
  462.     {
  463.     return ((cchCurrent == cchMax) ? 0 : 1);
  464.     }
  465.  
  466. /*
  467.  * Answers with the left edge of the (edit) field.
  468.  */
  469. COL ED::ColLeft()
  470.     {
  471.     return (IF::ColLeft()+dcol);
  472.     }
  473.  
  474. /*
  475.  * Answers with the current column position for this edit..
  476.  */
  477. COL ED::ColEdit()
  478.     {
  479.     return (ColLeft()+cchCurrent-1+DcolOffset());
  480.     }
  481.  
  482. /*
  483.  * Answers with the far right hand column for this edit..
  484.  */
  485. COL ED::ColRight()
  486.     {
  487.     return (ColLeft()+cchMax);
  488.     }
  489.  
  490. /*
  491.  *    Forces the field to be considered unchanged
  492.  */
  493. VOID ED::SetUnchanged()
  494.     {
  495.     fChanges = fFalse;
  496.     }
  497.  
  498. /*
  499.  * Answers if this field has changed.  Should consider if we care..
  500.  */
  501. BOOL ED::FModified()
  502.     {
  503.     return ((fCareAboutChanges) ? fChanges : fFalse);
  504.     }
  505.  
  506. /*
  507.  * Input validation routines.  This function evalutes the picture and
  508.  * the input character.  Answers if it is legal given the input..
  509.  *    If the character is NOT valid, but MAY be mapped onto a valid
  510.  *    character, that is done and we answer fTrue.
  511.  */
  512. BOOL ED::FValidChCh(CHAR &rch,CHAR chPicture)
  513.     {
  514.     /*
  515.      * PICTURE Templates:  
  516.      *                             X- Any printable character
  517.      *                             9- Digits
  518.      *                            A- Upper case letters, any other char
  519.      *                             a- Lower case letters, any other char
  520.      *                            U- Upper case letters only
  521.      *                            L- Lower case letters only
  522.      *                             N- Upper case Letters, Numbers
  523.      *                            n- Lower case Letters, Numbers
  524.      */
  525.     switch (chPicture)
  526.         {
  527.     case 'X':
  528.         return (isprint(rch));
  529.     case '9':
  530.         return (isdigit(rch));
  531.     case 'A':
  532.         return (isalpha(rch) ? isupper(rch = toupper(rch)) : isprint(rch));
  533.     case 'a':
  534.         return (isalpha(rch) ? islower(rch = tolower(rch)) : isprint(rch));
  535.     case 'U':
  536.         return (isupper(rch = toupper(rch)));
  537.     case 'L':
  538.         return (islower(rch = tolower(rch)));
  539.     case 'N':
  540.         return (isalnum(rch));
  541.     default:
  542.         return (fFalse);
  543.         }
  544.     }
  545.  
  546. /*
  547.  *    Answers if the picture for the current position is "CONSTANT"
  548.  */
  549. BOOL ED::FIsConstantPic()
  550.     {
  551.     BOOL fConstant = fTrue;
  552.     
  553.     switch (ChPicture())
  554.         {
  555.     case 'X':
  556.     case '9':
  557.     case 'A':
  558.     case 'a':
  559.     case 'U':
  560.     case 'L':
  561.     case 'N':
  562.         fConstant = fFalse;
  563.         }
  564.  
  565.     return (fConstant);
  566.     }
  567.  
  568. /*
  569.  *    Clear() either inserts the default value or clears the field.
  570.  */
  571. VOID ED::Clear()
  572.     {
  573.     Assert(sz != szNil);
  574.  
  575.     if (szDefault != szNil)
  576.         strcpy(sz,szDefault);
  577.     else
  578.         strcpy(sz,"");
  579.     }
  580.  
  581. /*
  582.  * Displays the delimiters for this edit..
  583.  */
  584. VOID ED::ShowDelimiters(CHAR chLeft,CHAR chRight)
  585.     {
  586.     rwnd.SetRowCol(RowEdit(),ColLeft()-1);
  587.     rwnd.PutCh(chLeft);
  588.     rwnd.SetRowCol(RowEdit(),ColLeft()+cchMax);
  589.     rwnd.PutCh(chRight);
  590.     }
  591.